| Conditions | 1 |
| Paths | 1 |
| Total Lines | 497 |
| Lines | 0 |
| Ratio | 0 % |
| Changes | 3 | ||
| Bugs | 0 | Features | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
| 1 | /* global wc_stripe_payment_request_params, Stripe */ |
||
| 2 | jQuery( function( $ ) { |
||
| 3 | 'use strict'; |
||
| 4 | |||
| 5 | var stripe = Stripe( wc_stripe_payment_request_params.stripe.key ); |
||
| 6 | |||
| 7 | /** |
||
| 8 | * Object to handle Stripe payment forms. |
||
| 9 | */ |
||
| 10 | var wc_stripe_payment_request = { |
||
| 11 | /** |
||
| 12 | * Get WC AJAX endpoint URL. |
||
| 13 | * |
||
| 14 | * @param {String} endpoint Endpoint. |
||
| 15 | * @return {String} |
||
| 16 | */ |
||
| 17 | getAjaxURL: function( endpoint ) { |
||
| 18 | return wc_stripe_payment_request_params.ajax_url |
||
| 19 | .toString() |
||
| 20 | .replace( '%%endpoint%%', 'wc_stripe_' + endpoint ); |
||
| 21 | }, |
||
| 22 | |||
| 23 | getCartDetails: function( paymentRequest ) { |
||
| 24 | var data = { |
||
| 25 | security: wc_stripe_payment_request_params.nonce.payment |
||
| 26 | }; |
||
| 27 | |||
| 28 | $.ajax({ |
||
| 29 | type: 'POST', |
||
| 30 | data: data, |
||
| 31 | url: wc_stripe_payment_request.getAjaxURL( 'get_cart_details' ), |
||
| 32 | success: function( response ) { |
||
| 33 | paymentRequest.update({ |
||
| 34 | total: response.order_data.total |
||
| 35 | }); |
||
| 36 | } |
||
| 37 | }); |
||
| 38 | }, |
||
| 39 | |||
| 40 | getAttributes: function() { |
||
| 41 | var select = $( '.variations_form' ).find( '.variations select' ), |
||
| 42 | data = {}, |
||
| 43 | count = 0, |
||
| 44 | chosen = 0; |
||
| 45 | |||
| 46 | select.each( function() { |
||
| 47 | var attribute_name = $( this ).data( 'attribute_name' ) || $( this ).attr( 'name' ); |
||
| 48 | var value = $( this ).val() || ''; |
||
| 49 | |||
| 50 | if ( value.length > 0 ) { |
||
| 51 | chosen ++; |
||
| 52 | } |
||
| 53 | |||
| 54 | count ++; |
||
| 55 | data[ attribute_name ] = value; |
||
| 56 | }); |
||
| 57 | |||
| 58 | return { |
||
| 59 | 'count' : count, |
||
| 60 | 'chosenCount': chosen, |
||
| 61 | 'data' : data |
||
| 62 | }; |
||
| 63 | }, |
||
| 64 | |||
| 65 | processSource: function( source, paymentRequestType ) { |
||
| 66 | var data = wc_stripe_payment_request.getOrderData( source, paymentRequestType ); |
||
| 67 | |||
| 68 | return $.ajax({ |
||
| 69 | type: 'POST', |
||
| 70 | data: data, |
||
| 71 | dataType: 'json', |
||
| 72 | url: wc_stripe_payment_request.getAjaxURL( 'create_order' ) |
||
| 73 | }); |
||
| 74 | }, |
||
| 75 | |||
| 76 | /** |
||
| 77 | * Get order data. |
||
| 78 | * |
||
| 79 | * @since 3.1.0 |
||
| 80 | * @version 4.0.0 |
||
| 81 | * @param {PaymentResponse} source Payment Response instance. |
||
|
|
|||
| 82 | * |
||
| 83 | * @return {Object} |
||
| 84 | */ |
||
| 85 | getOrderData: function( evt, paymentRequestType ) { |
||
| 86 | var source = evt.source; |
||
| 87 | var email = source.owner.email; |
||
| 88 | var phone = source.owner.phone; |
||
| 89 | var billing = source.owner.address; |
||
| 90 | var name = source.owner.name; |
||
| 91 | var shipping = evt.shippingAddress; |
||
| 92 | var data = { |
||
| 93 | _wpnonce: wc_stripe_payment_request_params.nonce.checkout, |
||
| 94 | billing_first_name: null !== name ? name.split( ' ' ).slice( 0, 1 ).join( ' ' ) : '', |
||
| 95 | billing_last_name: null !== name ? name.split( ' ' ).slice( 1 ).join( ' ' ) : '', |
||
| 96 | billing_company: '', |
||
| 97 | billing_email: null !== email ? email : evt.payerEmail, |
||
| 98 | billing_phone: null !== phone ? phone : evt.payerPhone.replace( '/[() -]/g', '' ), |
||
| 99 | billing_country: null !== billing ? billing.country : '', |
||
| 100 | billing_address_1: null !== billing ? billing.line1 : '', |
||
| 101 | billing_address_2: null !== billing ? billing.line2 : '', |
||
| 102 | billing_city: null !== billing ? billing.city : '', |
||
| 103 | billing_state: null !== billing ? billing.state : '', |
||
| 104 | billing_postcode: null !== billing ? billing.postal_code : '', |
||
| 105 | shipping_first_name: '', |
||
| 106 | shipping_last_name: '', |
||
| 107 | shipping_company: '', |
||
| 108 | shipping_country: '', |
||
| 109 | shipping_address_1: '', |
||
| 110 | shipping_address_2: '', |
||
| 111 | shipping_city: '', |
||
| 112 | shipping_state: '', |
||
| 113 | shipping_postcode: '', |
||
| 114 | shipping_method: [ null === evt.shippingOption ? null : evt.shippingOption.id ], |
||
| 115 | order_comments: '', |
||
| 116 | payment_method: 'stripe', |
||
| 117 | ship_to_different_address: 1, |
||
| 118 | terms: 1, |
||
| 119 | stripe_source: JSON.stringify( source ), |
||
| 120 | payment_request_type: paymentRequestType |
||
| 121 | }; |
||
| 122 | |||
| 123 | if ( shipping ) { |
||
| 124 | data.shipping_first_name = shipping.recipient.split( ' ' ).slice( 0, 1 ).join( ' ' ); |
||
| 125 | data.shipping_last_name = shipping.recipient.split( ' ' ).slice( 1 ).join( ' ' ); |
||
| 126 | data.shipping_company = shipping.organization; |
||
| 127 | data.shipping_country = shipping.country; |
||
| 128 | data.shipping_address_1 = typeof shipping.addressLine[0] === 'undefined' ? '' : shipping.addressLine[0]; |
||
| 129 | data.shipping_address_2 = typeof shipping.addressLine[1] === 'undefined' ? '' : shipping.addressLine[1]; |
||
| 130 | data.shipping_city = shipping.city; |
||
| 131 | data.shipping_state = shipping.region; |
||
| 132 | data.shipping_postcode = shipping.postalCode; |
||
| 133 | } |
||
| 134 | |||
| 135 | return data; |
||
| 136 | }, |
||
| 137 | |||
| 138 | /** |
||
| 139 | * Generate error message HTML. |
||
| 140 | * |
||
| 141 | * @since 3.1.0 |
||
| 142 | * @version 4.0.0 |
||
| 143 | * @param {String} message Error message. |
||
| 144 | * @return {Object} |
||
| 145 | */ |
||
| 146 | getErrorMessageHTML: function( message ) { |
||
| 147 | return $( '<div class="woocommerce-error" />' ).text( message ); |
||
| 148 | }, |
||
| 149 | |||
| 150 | /** |
||
| 151 | * Abort payment and display error messages. |
||
| 152 | * |
||
| 153 | * @since 3.1.0 |
||
| 154 | * @version 4.0.0 |
||
| 155 | * @param {PaymentResponse} payment Payment response instance. |
||
| 156 | * @param {String} message Error message to display. |
||
| 157 | */ |
||
| 158 | abortPayment: function( payment, message ) { |
||
| 159 | payment.complete( 'fail' ); |
||
| 160 | |||
| 161 | $( '.woocommerce-error' ).remove(); |
||
| 162 | |||
| 163 | if ( wc_stripe_payment_request_params.is_product_page ) { |
||
| 164 | var element = $( '.product' ); |
||
| 165 | |||
| 166 | element.before( message ); |
||
| 167 | |||
| 168 | $( 'html, body' ).animate({ |
||
| 169 | scrollTop: element.prev( '.woocommerce-error' ).offset().top |
||
| 170 | }, 600 ); |
||
| 171 | } else { |
||
| 172 | var $form = $( '.shop_table.cart' ).closest( 'form' ); |
||
| 173 | |||
| 174 | $form.before( message ); |
||
| 175 | |||
| 176 | $( 'html, body' ).animate({ |
||
| 177 | scrollTop: $form.prev( '.woocommerce-error' ).offset().top |
||
| 178 | }, 600 ); |
||
| 179 | } |
||
| 180 | }, |
||
| 181 | |||
| 182 | /** |
||
| 183 | * Complete payment. |
||
| 184 | * |
||
| 185 | * @since 3.1.0 |
||
| 186 | * @version 4.0.0 |
||
| 187 | * @param {PaymentResponse} payment Payment response instance. |
||
| 188 | * @param {String} url Order thank you page URL. |
||
| 189 | */ |
||
| 190 | completePayment: function( payment, url ) { |
||
| 191 | wc_stripe_payment_request.block(); |
||
| 192 | |||
| 193 | payment.complete( 'success' ); |
||
| 194 | |||
| 195 | // Success, then redirect to the Thank You page. |
||
| 196 | window.location = url; |
||
| 197 | }, |
||
| 198 | |||
| 199 | block: function() { |
||
| 200 | $.blockUI({ |
||
| 201 | message: null, |
||
| 202 | overlayCSS: { |
||
| 203 | background: '#fff', |
||
| 204 | opacity: 0.6 |
||
| 205 | } |
||
| 206 | }); |
||
| 207 | }, |
||
| 208 | |||
| 209 | /** |
||
| 210 | * Update shipping options. |
||
| 211 | * |
||
| 212 | * @param {Object} details Payment details. |
||
| 213 | * @param {PaymentAddress} address Shipping address. |
||
| 214 | */ |
||
| 215 | updateShippingOptions: function( details, address ) { |
||
| 216 | var data = { |
||
| 217 | security: wc_stripe_payment_request_params.nonce.shipping, |
||
| 218 | country: address.country, |
||
| 219 | state: address.region, |
||
| 220 | postcode: address.postalCode, |
||
| 221 | city: address.city, |
||
| 222 | address: typeof address.addressLine[0] === 'undefined' ? '' : address.addressLine[0], |
||
| 223 | address_2: typeof address.addressLine[1] === 'undefined' ? '' : address.addressLine[1] |
||
| 224 | }; |
||
| 225 | |||
| 226 | return $.ajax({ |
||
| 227 | type: 'POST', |
||
| 228 | data: data, |
||
| 229 | url: wc_stripe_payment_request.getAjaxURL( 'get_shipping_options' ) |
||
| 230 | }); |
||
| 231 | }, |
||
| 232 | |||
| 233 | /** |
||
| 234 | * Updates the shipping price and the total based on the shipping option. |
||
| 235 | * |
||
| 236 | * @param {Object} details The line items and shipping options. |
||
| 237 | * @param {String} shippingOption User's preferred shipping option to use for shipping price calculations. |
||
| 238 | */ |
||
| 239 | updateShippingDetails: function( details, shippingOption ) { |
||
| 240 | var data = { |
||
| 241 | security: wc_stripe_payment_request_params.nonce.update_shipping, |
||
| 242 | shipping_method: [ shippingOption.id ] |
||
| 243 | }; |
||
| 244 | |||
| 245 | return $.ajax({ |
||
| 246 | type: 'POST', |
||
| 247 | data: data, |
||
| 248 | url: wc_stripe_payment_request.getAjaxURL( 'update_shipping_method' ) |
||
| 249 | }); |
||
| 250 | }, |
||
| 251 | |||
| 252 | /** |
||
| 253 | * Adds the item to the cart and return cart details. |
||
| 254 | * |
||
| 255 | */ |
||
| 256 | addToCart: function() { |
||
| 257 | var product_id = $( '.single_add_to_cart_button' ).val(); |
||
| 258 | |||
| 259 | // Check if product is a variable product. |
||
| 260 | if ( $( '.single_variation_wrap' ).length ) { |
||
| 261 | product_id = $( '.single_variation_wrap' ).find( 'input[name="product_id"]' ).val(); |
||
| 262 | } |
||
| 263 | |||
| 264 | var data = { |
||
| 265 | security: wc_stripe_payment_request_params.nonce.add_to_cart, |
||
| 266 | product_id: product_id, |
||
| 267 | qty: $( '.quantity .qty' ).val(), |
||
| 268 | attributes: $( '.variations_form' ).length ? wc_stripe_payment_request.getAttributes().data : [] |
||
| 269 | }; |
||
| 270 | |||
| 271 | return $.ajax({ |
||
| 272 | type: 'POST', |
||
| 273 | data: data, |
||
| 274 | url: wc_stripe_payment_request.getAjaxURL( 'add_to_cart' ) |
||
| 275 | }); |
||
| 276 | }, |
||
| 277 | |||
| 278 | clearCart: function() { |
||
| 279 | var data = { |
||
| 280 | 'security': wc_stripe_payment_request_params.nonce.clear_cart |
||
| 281 | }; |
||
| 282 | |||
| 283 | return $.ajax({ |
||
| 284 | type: 'POST', |
||
| 285 | data: data, |
||
| 286 | url: wc_stripe_payment_request.getAjaxURL( 'clear_cart' ), |
||
| 287 | success: function( response ) {} |
||
| 288 | }); |
||
| 289 | }, |
||
| 290 | |||
| 291 | getRequestOptionsFromLocal: function() { |
||
| 292 | return { |
||
| 293 | total: wc_stripe_payment_request_params.product.total, |
||
| 294 | currency: wc_stripe_payment_request_params.checkout.currency_code, |
||
| 295 | country: wc_stripe_payment_request_params.checkout.country_code, |
||
| 296 | requestPayerName: true, |
||
| 297 | requestPayerEmail: true, |
||
| 298 | requestPayerPhone: true, |
||
| 299 | requestShipping: wc_stripe_payment_request_params.product.requestShipping, |
||
| 300 | displayItems: wc_stripe_payment_request_params.product.displayItems |
||
| 301 | }; |
||
| 302 | }, |
||
| 303 | |||
| 304 | /** |
||
| 305 | * Starts the payment request |
||
| 306 | * |
||
| 307 | * @since 4.0.0 |
||
| 308 | * @version 4.0.0 |
||
| 309 | */ |
||
| 310 | startPaymentRequest: function( cart ) { |
||
| 311 | var paymentDetails, |
||
| 312 | options; |
||
| 313 | |||
| 314 | if ( wc_stripe_payment_request_params.is_product_page ) { |
||
| 315 | options = wc_stripe_payment_request.getRequestOptionsFromLocal(); |
||
| 316 | |||
| 317 | paymentDetails = options; |
||
| 318 | } else { |
||
| 319 | options = { |
||
| 320 | total: cart.order_data.total, |
||
| 321 | currency: cart.order_data.currency, |
||
| 322 | country: cart.order_data.country_code, |
||
| 323 | requestPayerName: true, |
||
| 324 | requestPayerEmail: true, |
||
| 325 | requestPayerPhone: true, |
||
| 326 | requestShipping: cart.shipping_required ? true : false, |
||
| 327 | displayItems: cart.order_data.displayItems |
||
| 328 | }; |
||
| 329 | |||
| 330 | paymentDetails = cart.order_data; |
||
| 331 | } |
||
| 332 | |||
| 333 | var paymentRequest = stripe.paymentRequest( options ); |
||
| 334 | var paymentRequestType = ''; |
||
| 335 | |||
| 336 | |||
| 337 | var elements = stripe.elements({ locale: wc_stripe_payment_request_params.button.locale }); |
||
| 338 | var prButton = elements.create( 'paymentRequestButton', { |
||
| 339 | paymentRequest: paymentRequest, |
||
| 340 | style: { |
||
| 341 | paymentRequestButton: { |
||
| 342 | type: wc_stripe_payment_request_params.button.type, |
||
| 343 | theme: wc_stripe_payment_request_params.button.theme, |
||
| 344 | height: wc_stripe_payment_request_params.button.height + 'px' |
||
| 345 | }, |
||
| 346 | } |
||
| 347 | }); |
||
| 348 | |||
| 349 | // Check the availability of the Payment Request API first. |
||
| 350 | paymentRequest.canMakePayment().then( function( result ) { |
||
| 351 | if ( result ) { |
||
| 352 | paymentRequestType = result.applePay ? 'apple_pay' : 'payment_request_api'; |
||
| 353 | |||
| 354 | if ( wc_stripe_payment_request_params.is_product_page ) { |
||
| 355 | var addToCartButton = $( '.single_add_to_cart_button' ); |
||
| 356 | |||
| 357 | prButton.on( 'click', function( e ) { |
||
| 358 | // First check if product can be added to cart. |
||
| 359 | if ( addToCartButton.is( '.disabled' ) ) { |
||
| 360 | e.preventDefault(); |
||
| 361 | if ( addToCartButton.is( '.wc-variation-is-unavailable' ) ) { |
||
| 362 | window.alert( wc_add_to_cart_variation_params.i18n_unavailable_text ); |
||
| 363 | } else if ( addToCartButton.is( '.wc-variation-selection-needed' ) ) { |
||
| 364 | window.alert( wc_add_to_cart_variation_params.i18n_make_a_selection_text ); |
||
| 365 | } |
||
| 366 | } else { |
||
| 367 | wc_stripe_payment_request.addToCart(); |
||
| 368 | } |
||
| 369 | }); |
||
| 370 | |||
| 371 | $( document.body ).on( 'woocommerce_variation_has_changed', function() { |
||
| 372 | $( '#wc-stripe-payment-request-button' ).block({ message: null }); |
||
| 373 | |||
| 374 | $.when( wc_stripe_payment_request.getSelectedProductData() ).then( function( response ) { |
||
| 375 | $.when( paymentRequest.update({ |
||
| 376 | total: response.total, |
||
| 377 | displayItems: response.displayItems |
||
| 378 | }) ).then( function() { |
||
| 379 | $( '#wc-stripe-payment-request-button' ).unblock(); |
||
| 380 | }); |
||
| 381 | }); |
||
| 382 | }); |
||
| 383 | |||
| 384 | $( '.quantity' ).on( 'change', '.qty', function() { |
||
| 385 | $( '#wc-stripe-payment-request-button' ).block({ message: null }); |
||
| 386 | |||
| 387 | $.when( wc_stripe_payment_request.getSelectedProductData() ).then( function( response ) { |
||
| 388 | $.when( paymentRequest.update({ |
||
| 389 | total: response.total, |
||
| 390 | displayItems: response.displayItems |
||
| 391 | }) ).then( function() { |
||
| 392 | $( '#wc-stripe-payment-request-button' ).unblock(); |
||
| 393 | }); |
||
| 394 | }); |
||
| 395 | }); |
||
| 396 | } |
||
| 397 | |||
| 398 | if ( $( '#wc-stripe-payment-request-button' ).length ) { |
||
| 399 | prButton.mount( '#wc-stripe-payment-request-button' ); |
||
| 400 | $( '#wc-stripe-payment-request-button-separator' ).show(); |
||
| 401 | } |
||
| 402 | } else { |
||
| 403 | $( '#wc-stripe-payment-request-button' ).hide(); |
||
| 404 | $( '#wc-stripe-payment-request-button-separator' ).hide(); |
||
| 405 | } |
||
| 406 | }); |
||
| 407 | |||
| 408 | // Possible statuses success, fail, invalid_payer_name, invalid_payer_email, invalid_payer_phone, invalid_shipping_address. |
||
| 409 | paymentRequest.on( 'shippingaddresschange', function( evt ) { |
||
| 410 | $.when( wc_stripe_payment_request.updateShippingOptions( paymentDetails, evt.shippingAddress ) ).then( function( response ) { |
||
| 411 | evt.updateWith( { status: response.result, shippingOptions: response.shipping_options, total: response.total, displayItems: response.displayItems } ); |
||
| 412 | }); |
||
| 413 | }); |
||
| 414 | |||
| 415 | paymentRequest.on( 'shippingoptionchange', function( evt ) { |
||
| 416 | $.when( wc_stripe_payment_request.updateShippingDetails( paymentDetails, evt.shippingOption ) ).then( function( response ) { |
||
| 417 | if ( 'success' === response.result ) { |
||
| 418 | evt.updateWith( { status: 'success', total: response.total, displayItems: response.displayItems } ); |
||
| 419 | } |
||
| 420 | |||
| 421 | if ( 'fail' === response.result ) { |
||
| 422 | evt.updateWith( { status: 'fail' } ); |
||
| 423 | } |
||
| 424 | }); |
||
| 425 | }); |
||
| 426 | |||
| 427 | paymentRequest.on( 'source', function( evt ) { |
||
| 428 | // Check if we allow prepaid cards. |
||
| 429 | if ( 'no' === wc_stripe_payment_request_params.stripe.allow_prepaid_card && 'prepaid' === evt.source.card.funding ) { |
||
| 430 | wc_stripe_payment_request.abortPayment( evt, wc_stripe_payment_request.getErrorMessageHTML( wc_stripe_payment_request_params.i18n.no_prepaid_card ) ); |
||
| 431 | } else { |
||
| 432 | $.when( wc_stripe_payment_request.processSource( evt, paymentRequestType ) ).then( function( response ) { |
||
| 433 | if ( 'success' === response.result ) { |
||
| 434 | wc_stripe_payment_request.completePayment( evt, response.redirect ); |
||
| 435 | } else { |
||
| 436 | wc_stripe_payment_request.abortPayment( evt, response.messages ); |
||
| 437 | } |
||
| 438 | }); |
||
| 439 | } |
||
| 440 | }); |
||
| 441 | }, |
||
| 442 | |||
| 443 | getSelectedProductData: function() { |
||
| 444 | var product_id = $( '.single_add_to_cart_button' ).val(); |
||
| 445 | |||
| 446 | // Check if product is a variable product. |
||
| 447 | if ( $( '.single_variation_wrap' ).length ) { |
||
| 448 | product_id = $( '.single_variation_wrap' ).find( 'input[name="product_id"]' ).val(); |
||
| 449 | } |
||
| 450 | |||
| 451 | var data = { |
||
| 452 | security: wc_stripe_payment_request_params.nonce.get_selected_product_data, |
||
| 453 | product_id: product_id, |
||
| 454 | qty: $( '.quantity .qty' ).val(), |
||
| 455 | attributes: $( '.variations_form' ).length ? wc_stripe_payment_request.getAttributes().data : [] |
||
| 456 | }; |
||
| 457 | |||
| 458 | return $.ajax({ |
||
| 459 | type: 'POST', |
||
| 460 | data: data, |
||
| 461 | url: wc_stripe_payment_request.getAjaxURL( 'get_selected_product_data' ) |
||
| 462 | }); |
||
| 463 | }, |
||
| 464 | |||
| 465 | /** |
||
| 466 | * Initialize event handlers and UI state |
||
| 467 | * |
||
| 468 | * @since 4.0.0 |
||
| 469 | * @version 4.0.0 |
||
| 470 | */ |
||
| 471 | init: function() { |
||
| 472 | var data = { |
||
| 473 | security: wc_stripe_payment_request_params.nonce.payment |
||
| 474 | }; |
||
| 475 | |||
| 476 | $.ajax({ |
||
| 477 | type: 'POST', |
||
| 478 | data: data, |
||
| 479 | url: wc_stripe_payment_request.getAjaxURL( 'get_cart_details' ), |
||
| 480 | success: function( response ) { |
||
| 481 | wc_stripe_payment_request.startPaymentRequest( response ); |
||
| 482 | } |
||
| 483 | }); |
||
| 484 | }, |
||
| 485 | }; |
||
| 486 | |||
| 487 | wc_stripe_payment_request.init(); |
||
| 488 | |||
| 489 | // We need to refresh payment request data when total is updated. |
||
| 490 | $( document.body ).on( 'updated_cart_totals', function() { |
||
| 491 | wc_stripe_payment_request.init(); |
||
| 492 | }); |
||
| 493 | |||
| 494 | // We need to refresh payment request data when total is updated. |
||
| 495 | $( document.body ).on( 'updated_checkout', function() { |
||
| 496 | wc_stripe_payment_request.init(); |
||
| 497 | }); |
||
| 498 | }); |
||
| 499 |